package xfuzzy.xfhl.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;

import xfuzzy.lang.Operatorset;
import xfuzzy.xfds.XfdsDataSet;
import xfuzzy.xfds.XfdsParser;
import xfuzzy.xfhl.model.hierStruct.XfhlHierStruct;
import xfuzzy.xfhl.model.spec.XfhlOperSet;

/**
 * 
 * @author Sergio Cala Cordero
 * 
 */

public class XfhlConfig {

	/**
	 * Fichero en el que se encuentra el conjunto de datos a utilizar
	 */
	private File datasetfile;

	/**
	 * Conjunto de datos a utilizar
	 */
	private XfdsDataSet dataset;

	/**
	 * Fichero de salida
	 */
	private String outPutFile;

	/**
	 * Estilo comun a todas las variables de entrada
	 */
	private int styleInPut;

	/**
	 * Numero de funciones de petenencia de la variable de entrada
	 */
	private int mfs;

	/**
	 * El algoritmo de ajuste elegido
	 */
	private int algorithm;

	/**
	 * Parametro Initial Update del algoritmo
	 */
	private double iniUpd;

	/**
	 * Parametro Increase Factor del algoritmo
	 */
	private double incFact;

	/**
	 * Parametro Decrease Factor del algoritmo
	 */
	private double decFact;

	/**
	 * Operador AND
	 */
	private int andOperator;

	/**
	 * Operator Defuz
	 */
	private int DefuzOperator;

	/**
	 * Numero de entradas de nuestro modulo
	 */
	private int numVarEnt;

	/**
	 * Nombre del sistema
	 */
	private String nameSystem;

	/**
	 * Numero de iteraciones del algoritmo de ajuste
	 */
	private int numIterAjust;

	/**
	 * Numero de thread
	 */
	private int numThread;

	/**
	 * Variable que nos dice el n�mero de procesadores disponibles
	 */
	private int numProc;

	/**
	 * Numero de estructuras
	 */
	private int numStruct;

	private Operatorset operSet;

	/**
	 * Constructor por defecto
	 */
	public XfhlConfig() {

	}

	/**
	 * 
	 * @param nameSystem
	 *            Nombre que va a llevar el sistema final
	 * @param numIterAjus
	 *            Numero de iteraciones que va a utilizar el algoritmo
	 * @param numThread
	 *            Numero de hebras que va a utilizar el programa
	 * @param file
	 *            Archivo que contiene el data set
	 * @param iniUpd
	 *            Parametro Initial Update del algoritmo RPROP
	 * @param incFact
	 *            Parametro Increase Factor del algortimo RPROP
	 * @param decFact
	 *            Parametro Decrease Factor del algortimo RPROP
	 * @param andOperator
	 *            Operador AND
	 * @param defuzOperator
	 *            Operador de defuzificaci�n
	 * @param styleInPut
	 *            Estilo de las variables de entrada
	 * @param mfs
	 *            N�mero de varibales de funciones de las variables de entrada
	 * @param alg
	 *            Algoritmo de ajuste elegido
	 */

	public XfhlConfig(String nameSystem, int numIterAjus, int numThread, File file, double iniUpd, double incFact,
			double decFact, int andOperator, int defuzOperator, int styleInPut, int mfs, int alg) {
		setDataSet(file);

		this.nameSystem = nameSystem;
		this.numVarEnt = this.dataset.getNumberOfInputs();
		this.numIterAjust = numIterAjus;
		this.numThread = numThread;
		this.numStruct = XfhlHierStruct.numEstructuras(this.numVarEnt);
		this.algorithm = alg;
		this.iniUpd = iniUpd;
		this.incFact = incFact;
		this.decFact = decFact;
		this.andOperator = andOperator;
		this.DefuzOperator = defuzOperator;
		this.operSet = XfhlOperSet.create("OperSet", andOperator, defuzOperator);
		this.styleInPut = styleInPut;
		this.mfs = mfs;

		OperatingSystemMXBean mxbean;
		mxbean = ManagementFactory.getOperatingSystemMXBean();
		this.numProc = mxbean.getAvailableProcessors();

	}

	public boolean setDataSet(File file) {
		try {
			this.datasetfile = file;
			FileInputStream fis = new FileInputStream(datasetfile);
			XfdsParser parser = new XfdsParser(fis);
			XfdsDataSet ds = parser.parse();
			if (ds == null)
				return false;
			this.dataset = ds;
			return true;
		} catch (Exception ex) {
			return false;
		}
	}

	/**
	 * Obtiene el fichero del conjunto de datos
	 * 
	 * @return
	 */
	public File getDataSetFile() {
		return this.datasetfile;
	}

	public int getnumIterAjust() {
		return this.numIterAjust;
	}

	public int getnumVarEnt() {
		return this.numVarEnt;
	}

	public int getNumThread() {
		if (this.numThread == -1)
			return this.numProc;
		else
			return this.numThread;
	}

	public int getValueThread() {
		return this.numThread;
	}

	public void setNumThread(int numThread) {
		this.numThread = numThread;
	}

	public int getNumStruc() {
		return this.numStruct;
	}

	public void setNameSystem(String name) {
		this.nameSystem = name;
	}

	public String getNameSystem() {
		return this.nameSystem;
	}

	public Operatorset getOperSet() {
		return this.operSet;
	}

	public XfdsDataSet getDataSet() {
		return this.dataset;
	}

	public int getStileInput() {
		return this.styleInPut;
	}

	public int getMfs() {
		return this.mfs;
	}

	public String getOutputFile() {
		return this.outPutFile;
	}

	public double getIniUpd() {
		return this.iniUpd;

	}

	public double getIncFact() {
		return this.incFact;
	}

	public double getDecFact() {
		return this.decFact;
	}

	public int getAndOperator() {
		return this.andOperator;
	}

	public int getDefuzOperator() {
		return this.DefuzOperator;
	}

	public int getAlgorithm() {
		return this.algorithm;
	}

	public String toXML() {
		String eol = System.getProperty("line.separator", "\n");
		String code = "<xfuzzy>" + eol;
		code += "<xfhl system=\"" + this.nameSystem + "\">" + eol;

		code += "<dataset file=\"" + this.datasetfile.getAbsolutePath() + "\"></dataset>" + eol + eol;

		code += "<!-- NumThreads: " + eol + "default -> Number of available processors in the system. " + eol
				+ "tNumber of processors --> " + eol;
		String threads;
		if (this.numThread == -1)
			threads = "default";
		else
			threads = "" + this.numThread;
		code += "<threads numbers=\"" + threads + "\"></threads>" + eol + eol;

		code += "<!-- ALGORITHM: " + eol + "0: RProp " + eol + "1: Mardquardt Levenberg --> " + eol;

		code += "<learning algorithm =\"" + this.algorithm + "\"></learning>" + eol + eol;

		code += "<!-- STYLE: " + eol + "1: Free Triangles " + eol + "2: Free Shouldered Triangles "
				+ eol + "3: Free Gaussians " + eol + "4: Triangles Family " + eol
				+ "5: Shouldered-Triangular Family " + eol + "6: B-Splines Family --> " + eol;
		code += "<input_type style=\"" + this.styleInPut + "\" num_funct=\"" + this.mfs + "\"></input_type>" + eol
				+ eol;

		code += "\t\t<alg_param ini=\"" + this.iniUpd + "\" inc_fact=\"" + this.incFact + "\" dec_fact=\""
				+ this.decFact + "\"></alg_param>" + eol + eol;

		code += "\t\t<end_condition interations=\"" + this.numIterAjust + "\"></end_condition>" + eol + eol;

		code += "\t\t<!-- AND: " + eol + "\t\t\t0: Function MIN " + eol + "\t\t\t1: Function PROD " + eol
				+ "\t\t DEFUZ: " + eol + "\t\t\t0: Fuzzy Mean " + eol + "\t\t\t1: Weigthed Fuzzy Mean -->" + eol;

		code += "\t\t<operartor_set and=\"" + this.andOperator + "\" defuz=\"" + this.DefuzOperator
				+ "\"></operartor_set>" + eol + eol;

		code += "\t</xfhl>" + eol;
		code += "</xfuzzy>";

		return code;
	}

	/**
	 * 
	 * @param file
	 *            El archivo d�nde vamos a a�adir la configuraci�n
	 * @return
	 */
	public boolean save(File file) {
		String code = toXML();
		byte buf[] = code.getBytes();

		try {
			OutputStream stream = new FileOutputStream(file, true);
			stream.write(buf);
			stream.close();
		} catch (IOException e) {
			return false;
		}
		return true;
	}

}
